package com.xy.zookeeper.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class MyLock {
    private static String zkConnUrl = "127.0.0.1:2181";
    private CountDownLatch countDownLatch = new CountDownLatch(1);
    private ZooKeeper zooKeeper;
    private static final String LOCK_ROOT_PATH = "/Locks";
    private static final String LOCK_NODE_NAME = "Lock_";
    private String lockPath;

    public MyLock() throws IOException, InterruptedException {
        zooKeeper = new ZooKeeper(zkConnUrl, 5000, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                if (watchedEvent.getType() == Event.EventType.None) {
                    if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                        System.out.println("zookeeper已连接");
                        countDownLatch.countDown();
                    }
                }
            }
        });
        countDownLatch.await();
    }
    //获取锁
    public void acquireLock() throws KeeperException, InterruptedException {
        createLock();
        attemptLock();
    }

    private Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
                synchronized (this) {
                    notifyAll();
                }
            }
        }
    };
    //创建锁节点
    private void createLock() throws KeeperException, InterruptedException {
        //判断Locks是否存在
        Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, false);
        if (stat == null) {
            zooKeeper.create(LOCK_ROOT_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        //创建临时有序节点
        lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(lockPath + " 临时有序节点创建成功！");
    }
    //尝试获取锁
    private void attemptLock() throws KeeperException, InterruptedException {
        //获取Locks节点下的所有子节点
        List<String> list = zooKeeper.getChildren(LOCK_ROOT_PATH, false);
        Collections.sort(list);
        int index = list.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1));
        if (index == 0) {
            System.out.println("获取锁成功");
            return;
        } else {
            String path = list.get(index - 1);
            Stat stat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + path, watcher);
            if (stat == null) {
                attemptLock();
            } else {
                synchronized (watcher) {
                    watcher.wait();
                }
                attemptLock();
            }
        }
    }
    //释放锁
    public void releaseLock() throws KeeperException, InterruptedException {
        zooKeeper.delete(this.lockPath, -1);
        zooKeeper.close();
        System.out.println("锁已释放");
    }

    public List<String> getChildren() throws KeeperException, InterruptedException {
        return zooKeeper.getChildren(LOCK_ROOT_PATH, false);
    }
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        MyLock lock = new MyLock();
        lock.createLock();
        List<String> list = lock.getChildren();
        System.out.println(list);
    }
}
